package com.supplychainapi.filter;

import com.alibaba.fastjson.JSON;
import com.joindata.inf.common.basic.exceptions.ServiceException;
import com.supplychainapi.common.CommonCode;
import com.supplychainapi.common.RestResponse;
import com.supplychainapi.common.exception.CustomException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.messaging.handler.HandlerMethod;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by wangziqi on 2017/9/21.
 */
@Configuration
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {

    private Logger logger = LogManager.getLogger(WebMvcConfigurer.class);


    //统一异常处理
    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
        exceptionResolvers.add(new HandlerExceptionResolver() {
            public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {
                if (e instanceof ServiceException) {//业务失败的异常，如“账号或密码错误”
                    logger.info("业务异常:{},接口地址:{}", e.getCause() == null ? e.getMessage() : e.getCause().getLocalizedMessage(), request.getRequestURI());
                    responseResult(response, RestResponse.fail(e));
                } else if (e instanceof CustomException) { // 自定义运行中异常用于捕获service中的异常
                    RestResponse rest = ((CustomException) e).getRestResponse();
                    responseResult(response, rest);
                } else if (e instanceof MissingServletRequestParameterException) { // 参数类型错误
                    String parameterName = ((MissingServletRequestParameterException) e).getParameterName();
                    String message = String.format("参数名 [%s]，参数必传", parameterName);
                    responseResult(response, RestResponse.fail(400, message));
                } else if (e instanceof MethodArgumentTypeMismatchException) { // 参数必传
                    String parameterName = ((MethodArgumentTypeMismatchException) e).getParameter().getParameterName();
                    String parameterType = ((MethodArgumentTypeMismatchException) e).getParameter().getParameterType().getTypeName();
                    String message = String.format("参数名 [%s] 类型 [%s]，参数类型不正确", parameterName, parameterType);
                    responseResult(response, RestResponse.fail(400, message));
                } else if (e instanceof ConstraintViolationException) { // 参数验证失败异常 使用springboot框架自带验证
                    Object message = ((ConstraintViolationException) e).getConstraintViolations()
                            .stream()
                            .map(ConstraintViolation::getMessage)
                            .collect(Collectors.toList());
                    List<String> messageList = (ArrayList<String>) message;
                    responseResult(response, RestResponse.fail(400, messageList.get(0)));
                } else if (e instanceof NoHandlerFoundException) {
                    logger.info("接口请求异常:{}",e.getMessage());
                    responseResult(response, RestResponse.fail(e));
                } else if (e instanceof ServletException) {
                    logger.info("servlet异常:{}",e.getMessage());
                    responseResult(response, RestResponse.fail(e));
                } else if(e instanceof DuplicateKeyException){
                    logger.info("mybatis异常:{}",e.getMessage());
                    responseResult(response, RestResponse.fail(500, Integer.valueOf(CommonCode.DuplicateKey_ERROR.getCode()),CommonCode.DuplicateKey_ERROR.getDesc()));
                } else {
                    String message;
                    if (handler instanceof HandlerMethod) {
                        HandlerMethod handlerMethod = (HandlerMethod) handler;
                        message = String.format("接口 [%s] 出现异常，方法：%s.%s，异常摘要：%s",
                                request.getRequestURI(),
                                handlerMethod.getBean().getClass().getName(),
                                handlerMethod.getMethod().getName(),
                                e.getMessage());
                    } else {
                        message = e.getMessage();
                    }
                    if (message == null) message = "异常信息不存在";
                    responseResult(response, RestResponse.fail(500,message));
                    logger.error(message, e);
                }
                return new ModelAndView();
            }
        });
    }

    private void responseResult(HttpServletResponse response, RestResponse result) {
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-type", "application/json;charset=UTF-8");
        response.setStatus(200);
        try {
            response.getWriter().write(JSON.toJSONString(result));
        } catch (IOException ex) {
            logger.error(ex.getMessage());
        }
    }
}
